home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / nshellmegasource1.50 / mega src / commands / ls.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-26  |  13.3 KB  |  625 lines  |  [TEXT/KAHL]

  1. /* ========== the commmand file: ==========
  2.  
  3.     ls.c
  4.     
  5.     Copyright (c) 1994 Newport Software Development
  6.     
  7.     You may distribute unmodified copies of this file for
  8.     noncommercial purposes.  You may use this file as a
  9.     reference when writing your own nShell(tm) commands.
  10.     
  11.     All other rights are reserved.
  12.     
  13.    ========== the commmand file: ========== */
  14.  
  15. #ifdef __MWERKS__            // Get the appropriate A4 stuff
  16. #include <A4Stuff.h>
  17. #else
  18. #include <SetUpA4.h>
  19. #endif
  20.  
  21. #include <Packages.h>
  22.  
  23. #include "nshc.h"
  24. #include "walk_utl.h"
  25.  
  26. #include "arg_utl.proto.h"
  27. #include "buf_utl.proto.h"
  28. #include "nshc_utl.proto.h"
  29. #include "str_utl.proto.h"
  30. #include "fss_utl.proto.h"
  31. #include "walk_utl.proto.h"
  32.  
  33. /* ======================================== */
  34.  
  35. #define IS_A_DIRECTORY    fpb->ioFlAttrib & 16
  36.  
  37. // define the walking states
  38.  
  39. typedef enum { ls_dont_walk, ls_walk } t_walks;
  40.  
  41. // data definition - this struct is the root of all data
  42.  
  43. typedef struct {
  44.  
  45.     short        arg;                // position in arg list
  46.     
  47.     short        first_time;            // 1 on first pass
  48.     short        was_dir;            // 1 when a last item was a dir
  49.     
  50.     int            option_c;            // 1 when -c option is used
  51.     int            option_l;            // 1 when -l option is used
  52.     int            option_R;            // 1 when -R option is used
  53.     
  54.     char        time_flag;            // contians time flag (m=modified,g=creation,b=backup)
  55.     long        cols;                // number of columns for -c option
  56.     
  57.     t_walk_hndl    wData;                // storage for the walk structure
  58.     t_walks        walk_state;            // ls walk state
  59.  
  60. } t_ls_data;
  61.  
  62. typedef    t_ls_data    **t_ls_hndl;
  63.  
  64. /* ======================================== */
  65.  
  66. // local prototypes
  67.  
  68. OSErr ls_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  69. OSErr ls_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  70. OSErr ls_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  71. void  ls_shift_args( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, short arg, short distance );
  72. OSErr ls_one( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_ls_hndl lsData );
  73. OSErr ls_many( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_ls_hndl lsData );
  74. OSErr ls_get_path(  short vRefNum, long DirID, Str255 s );
  75. OSErr ls_display( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_ls_hndl lsData, FSSpec *fss );
  76.  
  77. /* ======================================== */
  78.  
  79. static void lsHeader( t_nshc_calls *nshc_calls, t_ls_hndl lsData )
  80. {
  81.     switch( (**lsData).time_flag ) {
  82.         case 'g' :
  83.             buf_putStr( "\p Crea Type RSize DSize  Creation Date       Name" );
  84.             break;
  85.         case 'b' :
  86.             buf_putStr( "\p Crea Type RSize DSize  Backup Date         Name" );
  87.             break;
  88.         default :
  89.             buf_putStr( "\p Crea Type RSize DSize  Modification Date   Name" );
  90.             break;
  91.         }
  92.     buf_putStr( "\p\r ---- ---- ----- ----- -------------------- ----\r" );
  93. }
  94.  
  95. /* ======================================== */
  96.  
  97. static void lsSize( t_nshc_calls *nshc_calls, t_ls_hndl lsData, long size)
  98. {
  99.     char    units;
  100.     int        blanks;
  101.     Str255    buf;
  102.  
  103.     units = ' ';
  104.  
  105.     if (size > 9999) {
  106.         size /= 1024;
  107.         units = 'k';
  108.         }
  109.  
  110.     if (size > 9999) {
  111.         size /= 1024;
  112.         units = 'M';
  113.         }
  114.  
  115.     NumToString(size, buf);
  116.  
  117.     for (blanks = 4 - buf[0]; blanks > 0; blanks--)
  118.         buf_putchar( ' ' );
  119.     buf_putStr( buf );
  120.  
  121.     buf_putchar( units );
  122. }
  123.  
  124. /* ======================================== */
  125.  
  126. static void lsLong( t_nshc_calls *nshc_calls, t_ls_hndl lsData, HFileInfo *fpb )
  127. {
  128.     int            i;
  129.     OSType        type;
  130.     char        *p;
  131.     long        value;
  132.     Str255        string;
  133.     
  134.     if ( IS_A_DIRECTORY ) {
  135.     
  136.         buf_putStr( "\p                      " );
  137.  
  138.         switch( (**lsData).time_flag ) {
  139.             case 'g' :
  140.                 value = ((DirInfo *)fpb)->ioDrCrDat;
  141.                 break;
  142.             case 'b' :
  143.                 value = ((DirInfo *)fpb)->ioDrBkDat;
  144.                 break;
  145.             default :
  146.                 value = ((DirInfo *)fpb)->ioDrMdDat;
  147.                 break;
  148.             }
  149.                 
  150.         }
  151.     else {
  152.     
  153.         buf_putchar( ' ' );
  154.  
  155.         type = fpb->ioFlFndrInfo.fdCreator;
  156.         p = (char *) &type;
  157.         for (i = 0; i < 4; i++)
  158.             buf_putchar( *p++ );
  159.         buf_putchar( ' ' );
  160.  
  161.         type = fpb->ioFlFndrInfo.fdType;
  162.         p = (char *) &type;
  163.         for (i = 0; i < 4; i++)
  164.             buf_putchar( *p++ );
  165.  
  166.         buf_putchar( ' ' );
  167.         lsSize( nshc_calls, lsData, fpb->ioFlRLgLen );
  168.         
  169.         buf_putchar( ' ' );
  170.         lsSize( nshc_calls, lsData, fpb->ioFlLgLen );
  171.  
  172.         switch( (**lsData).time_flag ) {
  173.             case 'g' :
  174.                 value = fpb->ioFlCrDat;
  175.                 break;
  176.             case 'b' :
  177.                 value = fpb->ioFlBkDat;
  178.                 break;
  179.             default :
  180.                 value = fpb->ioFlMdDat;
  181.                 break;
  182.             }
  183.     }
  184.     
  185.     buf_putchar( ' ' );
  186.  
  187.     IUDateString( value, shortDate, string );
  188.     for (i = (8 - string[0]); i > 0; i--)
  189.         buf_putchar( ' ' );
  190.     buf_putStr( string );
  191.     buf_putchar( ' ' );
  192.  
  193.     IUTimeString( value, 1, string );
  194.     for (i = (11 - string[0]); i > 0; i--)
  195.         buf_putchar( ' ' );
  196.     buf_putStr( string );
  197.     buf_putchar( ' ' );
  198.         
  199. }
  200.  
  201. /* ======================================== */
  202.  
  203. void ls_shift_args( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, short arg, short distance )
  204. {
  205.     short        new_arg;
  206.  
  207.     new_arg = arg + distance;
  208.     
  209.     while ( new_arg < nshc_parms->argc ) {
  210.         nshc_parms->argv[ arg ] = nshc_parms->argv[ new_arg ];
  211.         arg++;
  212.         new_arg++;
  213.         }
  214.         
  215.     nshc_parms->argc -= distance;
  216. }
  217.  
  218. /* ======================================== */
  219.  
  220. OSErr ls_get_path(  short vRefNum, long DirID, Str255 s )
  221. {
  222.     CInfoPBRec    block;
  223.     Str255        directoryName;
  224.     int            error;
  225.  
  226.     *s = 0;
  227.     
  228.     if ( DirID == 1 )
  229.         return( 0 );
  230.     
  231.     block.dirInfo.ioNamePtr = directoryName;
  232.     block.dirInfo.ioDrParID = DirID;
  233.     
  234.     do {
  235.     
  236.         block.dirInfo.ioVRefNum = vRefNum;
  237.         block.dirInfo.ioFDirIndex = -1;
  238.         block.dirInfo.ioDrDirID = block.dirInfo.ioDrParID;
  239.  
  240.         error = PBGetCatInfo(&block,false);
  241.         
  242.         if ( ( s[0] + directoryName[0] + 1 ) > 255 )
  243.             error = 1;
  244.             
  245.         if (!error) {
  246.             pStrAppend(directoryName,"\p:");
  247.             pStrAppend(directoryName,s);
  248.             pStrCopy(s,directoryName);
  249.             }
  250.  
  251.     } while (!error && (block.dirInfo.ioDrDirID != fsRtDirID));
  252.  
  253.     return(error);
  254. }
  255.  
  256. /* ======================================== */
  257.  
  258. OSErr ls_one( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_ls_hndl lsData )
  259. {
  260.     OSErr        result;
  261.     FSSpec        fss;
  262.     t_walk_hndl wData;
  263.     Str255        path;
  264.     
  265.     if ( ( (**lsData).arg > 1 ) && ( (**lsData).arg >= nshc_parms->argc ) ) {
  266.         nshc_parms->action = nsh_stop;
  267.         return( 0 );
  268.         }
  269.     
  270.     if ( nshc_parms->argc > 1 )
  271.         result = arg_to_real_fss( nshc_parms, nshc_calls, (**lsData).arg, &fss );
  272.     else {
  273.         pStrCopy( path, "\p:" );
  274.         result = nshc_calls->NSH_path_expand( path );
  275.         if ( !result )
  276.             result = nshc_calls->NSH_path_to_FSSpec( path, &fss );
  277.         }
  278.  
  279.     (**lsData).arg++;
  280.     
  281.     if (result) {
  282.         nshc_parms->action = nsh_stop;
  283.         return( -1 );
  284.         }
  285.         
  286.     if ( (**lsData).option_R ) {
  287.         wData = walk_init( &fss );
  288.         
  289.         if ( !wData ) {
  290.             nshc_calls->NSH_putStr_err( "\pls: Could not init Walk Library.\r" );
  291.             nshc_parms->action = nsh_stop;
  292.             return( -1 );
  293.             }
  294.     
  295.         (**lsData).wData = wData;
  296.         (**lsData).walk_state = ls_walk;
  297.         
  298.         return( 0 );
  299.         }
  300.  
  301.     return( ls_display( nshc_parms, nshc_calls, lsData, &fss ) );
  302. }
  303.  
  304. /* ======================================== */
  305.  
  306. OSErr ls_many( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_ls_hndl lsData )
  307. {
  308.     short        i;
  309.     long        size;
  310.     short        level;
  311.     short        isDir;
  312.     FSSpec        fss;
  313.     OSErr        error;
  314.     t_walk_hndl wData;
  315.     FInfo        fndrInfo;
  316.     
  317.     wData = (**lsData).wData;
  318.     
  319.     if ( !wData ) {
  320.         nshc_calls->NSH_putStr_err( "\pls: Missing data.\r" );
  321.         nshc_parms->action = nsh_stop;
  322.         return( -1 );
  323.         }
  324.         
  325.     do
  326.         
  327.         error = walk_next( wData, &fss, &level, &isDir );
  328.         
  329.     while ( !error && !isDir );
  330.     
  331.     if (error) {
  332.         (**lsData).walk_state = ls_dont_walk;
  333.         DisposeHandle( wData );
  334.         (**lsData).wData = 0L;
  335.         return(0);
  336.         }
  337.  
  338.     return( ls_display( nshc_parms, nshc_calls, lsData, &fss ) );
  339. }
  340.  
  341. /* ======================================== */
  342.  
  343. OSErr ls_display( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_ls_hndl lsData, FSSpec *fss )
  344. {
  345.     CInfoPBRec        cipbr;
  346.     HFileInfo        *fpb;
  347.     short            idx;
  348.     Str255            localPath;
  349.     long            foundDir;
  350.     int                ci, cmax;
  351.     int                count, blanks;
  352.     
  353.     // set up data block
  354.     
  355.     fpb = (HFileInfo *)&cipbr;
  356.     fpb->ioFDirIndex = 0;
  357.     fpb->ioVRefNum = fss->vRefNum;
  358.     fpb->ioDirID = fss->parID;
  359.     fpb->ioNamePtr = localPath;
  360.     pStrCopy( localPath, fss->name );
  361.  
  362.     if (PBGetCatInfo( &cipbr, FALSE )) {
  363.         nshc_calls->NSH_putStr_err("\pls: File or directory not found.\r");
  364.         return(1);
  365.         }
  366.         
  367.     // save id of found dir
  368.         
  369.     foundDir = fpb->ioDirID;
  370.     
  371.     // display the data
  372.  
  373.     if ( (**lsData).first_time && (**lsData).option_l )
  374.         lsHeader( nshc_calls, lsData );
  375.         
  376.     if ( IS_A_DIRECTORY ) {
  377.  
  378.         if ( ( nshc_parms->argc > 2 ) || ((**lsData).walk_state == ls_walk ) ) {
  379.         
  380.             buf_putStr( "\p\rDir = " );
  381.             ls_get_path( fss->vRefNum, foundDir, localPath );
  382.             buf_putStr( localPath );
  383.             buf_putchar( '\r' );
  384.             
  385.             }
  386.  
  387.         cmax = 0;
  388.         
  389.         if ( (**lsData).option_c )
  390.             for (idx = 1; TRUE; idx++) {
  391.                 fpb->ioVRefNum = fss->vRefNum;
  392.                 fpb->ioDirID = foundDir;
  393.                 fpb->ioFDirIndex = idx;
  394.                 if (PBGetCatInfo( &cipbr, FALSE ))
  395.                     break;
  396.                 ci = localPath[0] + 2;
  397.                 if (ci > cmax)
  398.                     cmax = ci;
  399.                 }
  400.                 
  401.         blanks = 0;
  402.         count = 0;
  403.  
  404.         for( idx=1; TRUE; idx++) {
  405.         
  406.             fpb->ioVRefNum = fss->vRefNum;
  407.             fpb->ioDirID = foundDir;
  408.             fpb->ioFDirIndex = idx;
  409.         
  410.             if (PBGetCatInfo( &cipbr, FALSE )) break;
  411.             
  412.             if ( (**lsData).option_l )
  413.                 lsLong( nshc_calls, lsData, fpb );
  414.  
  415.             if ( (**lsData).option_c ) {
  416.                 while (blanks--)
  417.                     buf_putchar( ' ' );
  418.                 blanks = cmax - localPath[0];
  419.                 }
  420.  
  421.             buf_putStr( localPath );
  422.  
  423.             if ( IS_A_DIRECTORY ) {
  424.                 buf_putchar( ':' );
  425.                 blanks--;
  426.                 }
  427.                 
  428.             if ( (**lsData).option_c ) {
  429.                 count++;
  430.                 if ( count >= (**lsData).cols ) {
  431.                     buf_putchar( '\r' );
  432.                     count = 0;
  433.                     blanks = 0;
  434.                     }
  435.                 }
  436.             else
  437.                 buf_putchar( '\r' );
  438.             
  439.             }
  440.             
  441.         if ( count )
  442.             buf_putchar( '\r' );
  443.             
  444.         (**lsData).was_dir = 1;
  445.  
  446.         }
  447.     else {
  448.         if ( (**lsData).was_dir )
  449.             buf_putchar( '\r' );
  450.         if ( (**lsData).option_l )
  451.             lsLong( nshc_calls, lsData, fpb );
  452.         buf_putStr( localPath );
  453.         buf_putchar( '\r' );
  454.         (**lsData).was_dir = 0;
  455.         }
  456.         
  457.     (**lsData).first_time = 0;
  458.     
  459.     return(0);
  460. }
  461.  
  462. /* ======================================== */
  463.  
  464. OSErr ls_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  465. {
  466.     short        arg;
  467.     short        usage;
  468.     t_ls_hndl     lsData;
  469.  
  470.     // get data space
  471.  
  472.     lsData = (t_ls_hndl)NewHandleClear( sizeof( t_ls_data ) );
  473.  
  474.     if (!lsData) {
  475.         nshc_calls->NSH_putStr_err( "\pls: Could not allocate data.\r" );
  476.         nshc_parms->action = nsh_stop;
  477.         return( -1 );
  478.         }
  479.         
  480.     nshc_parms->data = (Handle)lsData;
  481.     
  482.     // set defaults
  483.     
  484.     usage = 0;    // good usage until determined otherwise
  485.  
  486.     (**lsData).arg = 1;                        // start at the arg = 1 position
  487.     (**lsData).walk_state = ls_dont_walk;    // start by initing a search
  488.     (**lsData).first_time = 1;                // put up headers on first pass
  489.  
  490.     // read main options from command line
  491.     
  492.     (**lsData).option_R = nshc_got_option( nshc_parms, 'R' );
  493.     (**lsData).option_l = nshc_got_option( nshc_parms, 'l' );
  494.  
  495.     (**lsData).time_flag = 'm';
  496.     if (nshc_got_option( nshc_parms, 'b' )) (**lsData).time_flag = 'b';
  497.     if (nshc_got_option( nshc_parms, 'g' )) (**lsData).time_flag = 'g';
  498.  
  499.     (**lsData).option_c = nshc_got_option( nshc_parms, 'c' );
  500.     
  501.     if ( arg = (**lsData).option_c )
  502.             if ( nshc_is_numeric_operand( nshc_parms, ++arg ) )
  503.             (**lsData).cols = arg_to_num( nshc_parms, arg );
  504.         else
  505.             usage = 1;
  506.             
  507.     if ( (**lsData).option_l )
  508.         (**lsData).option_c = 0;
  509.         
  510.     // if usage error, report problem and exit
  511.     
  512.     if (usage) {
  513.         nshc_calls->NSH_putStr_err("\pUsage: ls [<path1> <path2>...] [-c columns] [-l [-m] [-b] [-g]].\r");
  514.         nshc_parms->action = nsh_stop;
  515.         return( NSHC_ERR_PARMS );
  516.         }
  517.         
  518.     // remove options (already read) from arg list
  519.     
  520.     if ( arg = nshc_got_option( nshc_parms, 'c' ) )
  521.         ls_shift_args( nshc_parms, nshc_calls, arg, 2 );
  522.         
  523.     if ( arg = nshc_got_option( nshc_parms, 'R' ) )
  524.         ls_shift_args( nshc_parms, nshc_calls, arg, 1 );
  525.         
  526.     if ( arg = nshc_got_option( nshc_parms, 'l' ) )
  527.         ls_shift_args( nshc_parms, nshc_calls, arg, 1 );
  528.     
  529.     if ( arg = nshc_got_option( nshc_parms, 'g' ) )
  530.         ls_shift_args( nshc_parms, nshc_calls, arg, 1 );
  531.     
  532.     if ( arg = nshc_got_option( nshc_parms, 'b' ) )
  533.         ls_shift_args( nshc_parms, nshc_calls, arg, 1 );
  534.     
  535.     // set up walk library
  536.     
  537.     nshc_parms->action = nsh_continue;
  538. }
  539.  
  540. /* ======================================== */
  541.  
  542. OSErr ls_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  543. {
  544.     OSErr        result;
  545.     t_ls_hndl lsData;
  546.  
  547.     lsData = (t_ls_hndl)nshc_parms->data;
  548.  
  549.     if ( !lsData ) {
  550.         nshc_calls->NSH_putStr_err( "\pls: Missing data.\r" );
  551.         nshc_parms->action = nsh_stop;
  552.         return( -1 );
  553.         }
  554.  
  555.     if ( (**lsData).walk_state == ls_dont_walk )
  556.         result = ls_one( nshc_parms, nshc_calls, lsData );
  557.     else
  558.         result = ls_many( nshc_parms, nshc_calls, lsData );
  559.         
  560.     return( result );
  561. }
  562.  
  563. /* ======================================== */
  564.  
  565. OSErr ls_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  566. {
  567.     t_ls_hndl lsData;
  568.     t_walk_hndl wData;
  569.  
  570.     lsData = (t_ls_hndl)nshc_parms->data;
  571.     wData = (**lsData).wData;
  572.  
  573.     if (lsData)
  574.         DisposeHandle( lsData );
  575.  
  576.     if (wData)
  577.         DisposeHandle( wData );
  578.  
  579.     nshc_parms->action = nsh_idle;
  580. }
  581.  
  582. /* ======================================== */
  583.  
  584. void main(t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls)
  585. {
  586. #ifdef __MWERKS__
  587.     long oldA4  = SetCurrentA4();
  588. #else
  589.     RememberA0();
  590.     SetUpA4();
  591. #endif
  592.  
  593.     buf_init( nshc_calls );
  594.     
  595.     if (!nshc_bad_version( nshc_parms, nshc_calls, NSHC_VERSION )) {
  596.     
  597.          // otherwise, handle requests from the application
  598.     
  599.           switch (nshc_parms->action) {
  600.             case nsh_start:
  601.                 nshc_parms->result = ls_start( nshc_parms, nshc_calls );
  602.                 break;
  603.             case nsh_continue:
  604.                 nshc_parms->result = ls_continue( nshc_parms, nshc_calls );
  605.                 break;
  606.             case nsh_stop:
  607.                 nshc_parms->result = ls_stop( nshc_parms, nshc_calls );
  608.                 break;
  609.             default:
  610.                 nshc_parms->result = NSHC_NO_ERR;
  611.                 nshc_parms->action = nsh_idle;
  612.                 break;
  613.             }
  614.         
  615.         }
  616.         
  617.     buf_flush();
  618.     
  619. #ifdef __MWERKS__
  620.     SetA4(oldA4);
  621. #else
  622.     RestoreA4();
  623. #endif
  624. }
  625.